package com.coder.rental.security;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.NumberWithFormat;
import cn.hutool.core.date.DateTime;
import cn.hutool.jwt.JWTPayload;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.coder.rental.entity.User;
import com.coder.rental.utils.JwtUtils;
import com.coder.rental.utils.RedisUtils;
import com.coder.rental.utils.ResultCode;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;

@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    @Resource
    private RedisUtils redisUtils;

    /**
     * 当认证成功时，此方法会被调用。
     *
     * @param request        HttpServletRequest 对象，表示HTTP请求
     * @param response       HttpServletResponse 对象，表示HTTP响应
     * @param authentication Authentication 对象，包含认证信息
     * @throws IOException      当无法写入响应时抛出
     * @throws ServletException 当Servlet遇到问题时抛出
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        // 设置客户端的响应的内容类型是json
        response.setContentType("application/json;charset=utf-8");

        // 获取用户信息
        User user = (User) authentication.getPrincipal();

        // 生成token的处理
        // 创建一个包含用户信息的HashMap
        HashMap<String, Object> map = new HashMap<>() {
            {
                // 将用户名和用户ID放入HashMap中
                put("username", user.getUsername());
                put("userid", user.getId());
            }
        };
        // 生成token
        String token = JwtUtils.createToken(map);

        // 解析token获取过期时间
        NumberWithFormat claim = (NumberWithFormat) JwtUtils.parseToken(token).getClaim(JWTPayload.EXPIRES_AT);
        long expireTime = Convert.toDate(claim).getTime();

        // 创建认证结果对象
        AuthenticationResult authenticationResult = new AuthenticationResult(user.getId(), ResultCode.SUCCESS, token, expireTime);

        // 获取一个结果
        // 将认证结果对象序列化为JSON字符串
        String result = JSON.toJSONString(authenticationResult, SerializerFeature.DisableCircularReferenceDetect);

        // 获取输出流
        // 获取响应的输出流
        ServletOutputStream outputStream = response.getOutputStream();
        // 将结果写入输出流
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        outputStream.flush();
        outputStream.close();

        // 把token存到redis，设置过期时间
        // 生成token的Redis键
        String tokenKey = "token:" + token;
        long nowTime = DateTime.now().getTime();
        // 将token存入Redis，并设置过期时间
        redisUtils.set(tokenKey, token, (expireTime - nowTime) / 1000);
    }
}
